package com.maiji.cloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.maiji.cloud.controller.ShopingOrderController;
import com.maiji.cloud.entities.shopingmall.*;
import com.maiji.cloud.mapper.ShareOrderLogMapper;
import com.maiji.cloud.microservice.ActivityShareRuleConfigService;
import com.maiji.cloud.response.BaseDataResDto;
import com.maiji.cloud.response.BaseResDto;
import com.maiji.cloud.response.Status;
import com.maiji.cloud.response.login.ActivityShareRuleConfigResData;
import com.maiji.cloud.response.shopingmall.ShareOrderLogResData;
import com.maiji.cloud.service.CapitalMainService;
import com.maiji.cloud.service.ShareOrderHelpLogService;
import com.maiji.cloud.service.ShareOrderLogService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.service.ShopingOrderService;
import com.maiji.cloud.utils.Arith;
import com.maiji.cloud.utils.CommonIntValueEnum;
import com.maiji.cloud.utils.FlowTypeEnum;
import com.maiji.cloud.utils.UUID_MD5;
import org.apache.commons.lang.BooleanUtils;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional
public class ShareOrderLogServiceImpl extends ServiceImpl<ShareOrderLogMapper, ShareOrderLog> implements ShareOrderLogService {

    Logger logger = LoggerFactory.getLogger(ShareOrderLogServiceImpl.class);
    @Value("${realmName}")
    private String realmName;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private ShareOrderLogMapper shareOrderLogMapper;
    @Autowired
    private ShareOrderHelpLogService shareOrderHelpLogService;
    @Autowired
    private ActivityShareRuleConfigService asrcService;
    @Autowired
    private ShopingOrderService shopingOrderService;
    @Autowired
    private CapitalMainService capitalMainService;

    @Override
    public BaseDataResDto<ShareOrderLogResData> ifCanShareOrder(String orderId, String userId) {
        logger.info("ifCanShareOrder(orderId {}, userId {})", orderId, userId);
        ShareOrderLogResData shareOrderLogResData = shareOrderLogMapper.findById(orderId);
        if (shareOrderLogResData != null) return new BaseDataResDto(Status.SUCCESS).setData(shareOrderLogResData.setIfCan(true));
        ShopingOrder shopingOrder = shopingOrderService.selectById(orderId);
        ShareOrderLogResData data = new ShareOrderLogResData().setIfCan(false)
                .setOrderId(orderId).setOrderMoney(shopingOrder.getAmount());
        BaseDataResDto<ShareOrderLogResData> baseDataResDto = new BaseDataResDto<ShareOrderLogResData>(Status.SUCCESS).setData(data);
        Query query = new Query(Criteria.where("type").is(CommonIntValueEnum.MONGO_RULE_TYPE_ORDER.getValue()));
        ShareOrderRule shareOrderRule = mongoTemplate.findOne(query, ShareOrderRule.class, ShareOrderRule.TABLE_NAME);
        // 判断订单返现活动是否开启
        if (! shareOrderRule.getIsOpen()) return baseDataResDto;
        // 判断订单状态是否符合可以参与活动
//        if (shopingOrder.getStatus() == CommonIntValueEnum.SHOPPING_ORDER_STATUS_STAY_PAY.getValue()) return baseDataResDto;
        if (shopingOrder.getStatus() == CommonIntValueEnum.SHOPPING_ORDER_STATUS_ALREADY_CANCEL.getValue()) return baseDataResDto;
        if (shopingOrder.getRefundStatus() != CommonIntValueEnum.SHOPPING_ORDER_REFUND_NONE.getValue()) return baseDataResDto;
        Double amount = shopingOrder.getAmount();
        List<ShareOrderRuleSection> sectionList = shareOrderRule.getSections().parallelStream()
                .filter(section -> section.getOrderMoney() <= amount).sorted().collect(Collectors.toList());
        Optional<ShareOrderRuleSection> firstOptional = sectionList.parallelStream().findFirst();
        if (! firstOptional.isPresent()) return baseDataResDto;
        Double maxReturMoney = Arith.multiplys(2, amount, firstOptional.get().getMaxReturRatio());
        Date shareTime = new Date();
        Date endTime = new Date(shareTime.getTime() + Duration.ofHours(shareOrderRule.getHours()).toMillis());
        ShareOrderLog shareOrderLog = new ShareOrderLog().setUuId(UUID_MD5.getUUID()).setOrderId(orderId)
                .setUserId(userId).setMaxReturMoney(maxReturMoney).setOrderMoney(amount).setSettlement(false)
                .setEndTime(endTime).setTermination(false).setShareTime(shareTime);
        if (! insert(shareOrderLog)) return new BaseDataResDto<>(Status.ERROR.setMessage("保存活动记录失败！"));
        data = shareOrderLogMapper.findById(orderId);
        logger.info("ifCanShareOrder：return {}", JSON.toJSONString(data.setIfCan(true)));
        return baseDataResDto.setData(data.setIfCan(true));
    }

    @Override
    public BaseDataResDto<ShareOrderLogResData> findShareOrderLogById(String orderId, String userId) {
        ShareOrderLogResData shareOrderLogResData = shareOrderLogMapper.findById(orderId);
        if (shareOrderLogResData == null) return new BaseDataResDto<>(Status.PARAMETERERROR);
        ActivityShareRuleConfigResData ruleConfigResData = asrcService.getAsrcByType(
                CommonIntValueEnum.ACTIVITY_SHARE_RULE_CONFIG_TYPE_ORDER.getValue());
        if (ruleConfigResData != null) shareOrderLogResData.setRuleConfigResData(ruleConfigResData);
        if (StringUtil.isNotBlank(userId)) {
            Boolean canHelp = shareOrderHelpLogService.canHelp(userId, shareOrderLogResData.getUuId());
            shareOrderLogResData.setIsMine(userId.equals(shareOrderLogResData.getUserId()))
                    .setCanHelp(BooleanUtils.isTrue(canHelp) && ! shareOrderLogResData.getIsMine());
        }
        EntityWrapper<ShareOrderHelpLog> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("share_order_log_id", shareOrderLogResData.getUuId());
        entityWrapper.orderBy("helpMoney", false);
        List<ShareOrderHelpLog> shareOrderHelpLogs = shareOrderHelpLogService.selectList(entityWrapper);
        shareOrderLogResData.setHelpList(shareOrderHelpLogs).setRealmName(realmName);
        Double nowReturMoney = shareOrderHelpLogs.parallelStream().map(ShareOrderHelpLog::getHelpMoney)
                .reduce(Double.valueOf(0), (sol1, sol2) -> Arith.add(2, sol1, sol2));
        return new BaseDataResDto<ShareOrderLogResData>(Status.SUCCESS).setData(shareOrderLogResData.setNowReturMoney(nowReturMoney));
    }

    @Override
    public BaseDataResDto<Double> statisticShareOrderHelp(String helpId) {
        ShareOrderLog shareOrderLog = selectById(helpId);
        EntityWrapper<ShareOrderHelpLog> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("share_order_log_id", shareOrderLog.getUuId());
        Double totalHelpMoney = shareOrderHelpLogService.selectList(entityWrapper)
                .stream().map(ShareOrderHelpLog::getHelpMoney).reduce(Double.valueOf(0), (hm1, hm2) -> Arith.add(2, hm1, hm2));
        updateById(shareOrderLog.setReturMoney(totalHelpMoney).setSettlement(true));
        capitalMainService.updateCapitalMain(shareOrderLog.getUserId(), FlowTypeEnum.RETURNMONEY, totalHelpMoney.toString(),
                FlowTypeEnum.INCREASE, FlowTypeEnum.SHAREORDERHELP, shareOrderLog.getUuId());
        ShopingOrder shopingOrder = new ShopingOrder()
                .setUuId(shareOrderLog.getOrderId())
                .setShareOrder(true)
                .setShareOrderMoney(totalHelpMoney);
        shopingOrderService.updateById(shopingOrder);
        return new BaseDataResDto<Double>(Status.SUCCESS).setData(totalHelpMoney);
    }

    @Override
    public BaseDataResDto<ShareOrderRule> findShareOrderRule() {
        Query query = new Query(Criteria.where("type").is(CommonIntValueEnum.MONGO_RULE_TYPE_ORDER.getValue()));
        ShareOrderRule shareOrderRule = mongoTemplate.findOne(query, ShareOrderRule.class, ShareOrderRule.TABLE_NAME);
        return new BaseDataResDto<ShareOrderRule>(Status.SUCCESS).setData(shareOrderRule);
    }

    @Override
    public BaseResDto updShareOrderRule(ShareOrderRule shareOrderRule) {
        Query query = new Query(Criteria.where("type").is(CommonIntValueEnum.MONGO_RULE_TYPE_ORDER.getValue()));
        mongoTemplate.findAndRemove(query, ShareOrderRule.class, ShareOrderRule.TABLE_NAME);
        mongoTemplate.save(shareOrderRule, ShareOrderRule.TABLE_NAME);
        mongoTemplate.save(shareOrderRule, ShareOrderRule.TABLE_LOG_NAME);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<List<ShareOrderRule>> findAllShareOrderRuleLogs(List<Date> updateDates) {
        Query query = new Query(Criteria.where("type").is(CommonIntValueEnum.MONGO_RULE_TYPE_ORDER.getValue()));
        query.skip(1).with(new Sort(new Sort.Order(Sort.Direction.DESC,"updateDate")));
        Date startDate = updateDates.size() > 0 ? updateDates.get(0): null;
        Criteria updateDateCriteria = Criteria.where("updateDate");
        Boolean updFlag = false;
        if (startDate != null) {
            updateDateCriteria = updateDateCriteria.gte(startDate);
            updFlag = true;
        }
        Date endDate = updateDates.size() > 1 ? updateDates.get(1): null;
        if (endDate != null) {
            updateDateCriteria = updateDateCriteria.lte(endDate);
            updFlag = true;
        }
        if (updFlag) query.addCriteria(updateDateCriteria);
        if (startDate == null && endDate == null) query.limit(1);
        List<ShareOrderRule> shareOrderRules = mongoTemplate.find(query, ShareOrderRule.class, ShareOrderRule.TABLE_LOG_NAME);
        return new BaseDataResDto<List<ShareOrderRule>>(Status.SUCCESS).setData(shareOrderRules);
    }

}
